<?php
/**
 ***********************************************************************************************************************
 * 安能接口统一基础类
 * @author ldh
 ***********************************************************************************************************************
 */
namespace soa\partner\ane;

use artisan\http;
use soa\check\EnvCheck;
use soa\client;
use soa\common\RemoteDB;
use soa\partner\partnerCommon;
use soa\service;

/**
 * Class AneClient
 * @package soa\partner\ane
 */
class AneClient extends client
{
    const RESULT_iNFO = 'resultInfo';

    const SCAN_PARAMS = 'scanParams';

    const KEY = 'ane';

    const SECRET = '123456';

//    protected $service_url = 'http://kdpda.ane56.com/webservice/pdaServerRest/operate';//正式地址
//    protected $service_url = 'http://58.215.167.5:60216/webservice/pdaServerRest/operate';//测试地址
//    protected $service_url = 'http://58.215.167.212:60216/webservice/pdaServerRest/operate';//uat环境
    protected $service_url ='http://43.254.149.87:8080/webservice/pdaServerRest/operate';//正式环境地址

    protected $service_name = 'ane_api';

    protected $_timeout = 5;

    private $_option = [];

    private $requestType;

    private $typeMap = [
        'siteListService'                  => self::SCAN_PARAMS,//网点列表
        'siteServiceImpl'                  => self::RESULT_iNFO,//网点详情
        'provinceListService'              => self::RESULT_iNFO,//省信息
        'cityListService'                  => self::SCAN_PARAMS,//市信息
        'countyListService'                => self::SCAN_PARAMS,//区信息
        'signTypeService'                  => self::RESULT_iNFO,//签收类型
        'questionListService'              => self::RESULT_iNFO,//问题原因列表
        'billRuleService'                  => self::RESULT_iNFO,//单号规则
        'userListService'                  => self::RESULT_iNFO,//用户信息
        'pdaLoginServiceImpl'              => self::RESULT_iNFO,//巴枪登录
        'receiveScanService'               => self::RESULT_iNFO,//收件扫描
        'arriveScanServie'                 => self::RESULT_iNFO,//到件扫描
        'dispatchScanService'              => self::RESULT_iNFO,//派件扫描
        'signScanService'                  => self::RESULT_iNFO,//签收扫描
        'deliveryListService'              => self::RESULT_iNFO,//派件清单
        'queryEwbInfoService'              => self::RESULT_iNFO,//派件地址、电话
        'issueListService'                 => self::RESULT_iNFO,//本站物料信息,收件校验用
        'queryLimitSiteService'            => self::RESULT_iNFO,//获取发件、到件网点
        'queryNoteSiteServiceImpl'         => self::RESULT_iNFO,//获取问题件通知网点
        'arrivePackageScanDataServiceImpl' => self::RESULT_iNFO,//到包扫描
    ];

    public static $_codeMap = [
        200 => '成功',
        203 => '接口调用异常',
        401 => '请求失效',
        403 => '非法请求参数',
        404 => '失败',
        303 => '参数转换异常',
        405 => '摘要非法',
    ];

    public function __construct()
    {
        if(EnvCheck::isEnvOnlineTest() || EnvCheck::isEnv81() || '127.0.0.1' == $_SERVER['SERVER_ADDR']){
            $this->service_url = 'http://58.215.167.212:60216/webservice/pdaServerRest/operate';//uat环境
        }
        $this->_reset();
    }

    /**
     * 安能巴枪登录统一入口
     *
     * @param $empNo
     * @param $empPwd
     * @param $branchCode
     * @return array|bool|null
     */
    public final function login($empNo, $empPwd, $branchCode = 0)
    {
        if(empty($empNo) || empty($empPwd)){
            return [];
        }

        if(empty($branchCode)){
            $result = partnerCommon::getCmInfoByCmCode($empNo,'ane');
            if(!empty($result['branch_code'])){
                $branchCode = $result['branch_code'];
            }else{
                static::$_msg = '请输入网点编号!';
                return [];
            }
        }
        $branchInfo=service::branch()->getBranchByCode($branchCode,'ane');
        //logDebug($branchInfo,'ane_branch_info',true);
        if($branchInfo&&4==$branchInfo['type']){
            logDebug("empNo:{$empNo},empPwd:{$empPwd},branchcode:{$branchCode},分拨中心网点不允许使用巴枪!",'ane_forbid_login');
            static::$_msg = "分拨中心网点不允许使用巴枪,请联系你们网点客服({$branchCode})";
            return [];
        }

        $post = [
            'employeeNo' => $empNo ? : '',
            'pdaPwd'     => $empPwd ? : '',
            'siteCode'   => $branchCode ? : '',
        ];

        $result = $this->send('pdaLoginServiceImpl',$post);

        //status正常N,	锁定L,	删除D;
        //siteState站点状态（1：正常、0：暂停、-1：失效）
        if((!empty($result['siteState']))){
            switch($result['siteState']){
                case 0:
                    static::$_code = 1102;
                    static::$_msg = '站点状态：暂停';
                    return [];
                case -1:
                    static::$_code = 1102;
                    static::$_msg = '站点状态：失效';
                    return [];
            }
        }
        //判断status
        if(!empty($result['status'])){
            switch($result['status']){
                case 'L':
                    static::$_code = 1102;
                    static::$_msg = '该工号被锁定！';
                    return [];
                case 'D':
                    static::$_code = 1102;
                    static::$_msg = '该工号已被删除！';
                    return [];
            }
            return $result;
        }


        if($this->getCode() || !is_array($result) || empty($result)){
            logDebug(json_encode($post,JSON_UNESCAPED_UNICODE).'--'.$this->getResult(),'ane_login_fail');
            //$this->getCode();查看错误代码
            //$this->getMsg();查看错误原因
            //$this->getResult();查看原始返回
        }
        return [];
    }

    /**
     * @param $type
     * @param array $data
     * @param array $options
     * @return bool|null
     */
    public function send($type, $data = [], $options = [])
    {
        $this->_reset();

        $data = empty($data) ? '{}' : json_encode($data);
        $post = [
            'params'    => $data,
            'timestamp' => time() * 1000,//精确到毫秒13位
            'digest'    => base64_encode(md5($data . static::KEY . static::SECRET)),
            'type'      => $this->requestType = $type,
        ];

        $post = json_encode($post);

        $options['TIMEOUT'] = isset($options['TIMEOUT']) ? $options['TIMEOUT'] : $this->_timeout;
        $options['HTTPHEADER'] = isset($options['HTTPHEADER']) ? $options['HTTPHEADER'] : [
            'Content-Type: application/json;charset=UTF-8',
        ];
        $this->setHttpOption($options);

        return $this->post('', $post);
    }

    /**
     * @param $api
     * @param array $data
     * @param string $type
     * @return bool
     */
    protected function request($api, $data = [], $type = 'POST')
    {
        // 请求参数检测
        if(empty($this->service_url) || empty($type)) {
            return false;
        }
        // 请求内容检测
        if(empty($data) && !is_array($data)) {
            $data = [];
        }

        $time1 = time();

        $option = $this->getHttpOption();

        // 为自定义参数提供支持
        $api_url = empty($api) ? $this->service_url : $this->request_api($api);

        // 去除DELETE\PUT等类型，直接GET\POST容易处理
        switch ($type) {
            case 'POST':
                $response = http::post($api_url, $data, $option);
                break;
            case 'GET':
            default:
                $response = http::get($api_url, $data, $option);
                break;
        }
//        logDebug('返回值:'.$response.',请求参数:'.gettype($data).':'.$data,'ane_login_result',true);

        // 解析返回结果
        $ret = $this->parse($response);
        static::$_result = $response;

        // 设置状态码和消息
        static::$_msg   = $ret->msg;
        static::$_code  = $ret->code;
        static::$_error = $ret->error;

        // 错误判断 记录状态码小于1009的错误
        if($ret->error !== 0) {
            // 业务错误日志，取消记录
            if($this->getCode() < 1009) {
                $time2 = time();
                // 注：记录客户端名称（即项目名称）、错误消息、错误的接口（左侧不带/）、服务名称
                logError('[' . $this->requestType . ']' . $ret->msg . '耗时：'.($time2-$time1).$data, ltrim($this->requestType, '/'), $this->service_name);
            }
        }

        // 设置并且返回结果
        return static::$_data = $ret->data;
    }

    /**
     * @param string $result
     * @param string $code
     * @param string $msg
     * @param string $data
     * @return mixed
     */
    protected function parse($result = '', $code = 'resultCode', $msg = 'reason', $data = 'resultInfo')
    {
        if(isset($this->typeMap[$this->requestType])){
            $data = $this->typeMap[$this->requestType];
            $isJson = 1;
        }else{
            $data = self::RESULT_iNFO;
            $isJson = 0;
        }

        // 重置响应结果
        $this->_reset($result);

        // 重置服务结果
        $json = json_decode('{"error":0,"msg":"成功","code":0}');

        // 初始化最终返回数据
        $json->data = '';

        // 返回数据为空 注：可能连接超时、网络错误、服务器错误
        if(empty($result)) {
            $json->error += 1;
            $json->msg = '网络忙，请稍后重试[该服务或接口无返回]!';
            // 不能设置500错误，为了兼容负载均衡服务器，如果开发者抛出太多500以上600以下错误，会导致该台服务器被下线
            $json->code = 1000;
            return $json;
        }

        // 返回数据格式错误 注：返回数据不合法
        $arr = json_decode($result, true);
        if(json_last_error() != 0) {
            $json->error += 1;
            $json->msg = '该服务或接口返回结果无法解析:' . json_last_error() . (string)json_last_error_msg();
            $json->code = 422;
            return $json;
        }

        // 请求业务错误
        if(false === $arr['result'] || $arr[$code] != 200) {
            $json->error += 1;
            $json->msg = !empty($arr[$msg]) ? $arr[$msg] : (isset(self::$_codeMap[$arr[$code]]) ? self::$_codeMap[$arr[$code]] : '该服务或接口返回未知状态错误!');
//            $json->code = !isset($arr[$code]) ? 1020 : intval($arr[$code]);
            $json->code = 1020;
            if(isset($arr[$data])) {
                $json->data = $arr[$data];
            }
            return $json;
        }

        if(isset($arr[$data]) && $isJson) {
            if(self::SCAN_PARAMS == $data && $arr[$data]){
                $arr[$data] = gzdecode(base64_decode($arr[$data]));
            }
            $arr[$data] = json_decode($arr[$data],true);
            if(json_last_error() != 0) {
                $json->error += 1;
                $json->msg = '该接口返回数据无法解析:' . json_last_error() . (string)json_last_error_msg();
                $json->code = 422;
                return $json;
            }
        }

        // 设置正确状态码
        $json->code = 0;
        if(isset($arr[$data])) {
            $json->data = $arr[$data];
        }
        return $json;
    }

    /**
     * @param array $option
     */
    public function setHttpOption(array $option)
    {
        $option and $this->_option = $option;
    }

    /**
     * @return mixed
     */
    public function getHttpOption()
    {
        return $this->_option;
    }

    public static $_code = 1000;

    public static $_msg = '未知错误';

    public static $_error = 0;

    public static $_result = '';

    public static $_data = '';

    public function getCode()
    {
        return static::$_code;
    }

    public function getMsg()
    {
        return static::$_msg;
    }

    public function getResult()
    {
        return static::$_result;
    }

    public function getData()
    {
        return static::$_data;
    }

    public function getError()
    {
        return static::$_error;
    }
}